<!DOCTYPE html>
<html lang="en">
    <head>
        <!-- Global site tag (gtag.js) - Google Analytics -->
        <script async src="https://www.googletagmanager.com/gtag/js?id=UA-80202630-2"></script>
        <script>
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());

            gtag('config', 'UA-80202630-2');
        </script>

        <title>Fast XML Parser</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="static/css/font-awesome.min.css">
        <link rel="stylesheet" href="static/css/bootstrap.min.css">
        <link rel="stylesheet" href="static/css/prettify.min.css">
        <link rel="stylesheet" href="static/css/jquery-confirm.min.css">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.css" 
                integrity="sha512-uf06llspW44/LZpHzHT6qBOIVODjWtv4MxCricRxkzvopAlSWnTf6hpZTFxuuZcuNE9CBQhqE0Seu1CoRk84nQ==" 
                crossorigin="anonymous" 
                referrerpolicy="no-referrer" />

        <script src="static/js/jquery-3.2.1.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/6.65.7/codemirror.min.js" 
                integrity="sha512-8RnEqURPUc5aqFEN04aQEiPlSAdE0jlFS/9iGgUyNtwFnSKCXhmB6ZTNl7LnDtDWKabJIASzXrzD0K+LYexU9g==" 
                crossorigin="anonymous" 
                referrerpolicy="no-referrer"></script>
        <script src="static/js/bootstrap.min.js"></script>
        <!-- <script src="static/js/prettify.min.js"></script> -->
        <link rel="stylesheet" type="text/css" href="static/css/animate3.5.2.min.css">

        <script src="lib/fxp.min.js"></script>
        <script src="static/js/jquery-confirm.min.js"></script>
        <style>
            .CodeMirror{
                height: 100%;
                width: 100%;
            }
        </style>
    </head>
    <body>
    <body role="document" style="background-color: #2c3e50;">

        <div class="container-fluid">
            
            
            <div class="row" style="height: calc(100vh - 100px);">
                <div class="col-md-4" >
                    <span class="float-right" style="color: white"> <span id="lengthxml" style="margin:5px">0</span> bytes</span>
                    <textarea id="txtXml" name="xml" style="width: 100%; height: 100%" class="form-control" placeholder="Paste XML to parse in JS/JSON"></textarea>
                </div>
                <div class="col-md-4" style=" color: white;">
                        <div style="margin: 5px; padding: 5px;">
                                <a href="https://github.com/NaturalIntelligence/fast-xml-parser"><img class="bring-up" style="position: absolute; top: 0; left: -15px; border: 0; z-index: 1" src="https://camo.githubusercontent.com/121cd7cbdc3e4855075ea8b558508b91ac463ac2/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f6c6566745f677265656e5f3030373230302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_left_green_007200.png"></a>
                                <h1 style="color:white;" class="text-center">Fast XML Parser <a class="github-button" href="https://github.com/NaturalIntelligence/fast-xml-parser" data-show-count="true" aria-label="Star NaturalIntelligence/fast-xml-parser on GitHub">Star</a></h1>
                                <p style="color:white;" class="text-center">The fastest parser for browsers <!-- Place this tag where you want the button to render. -->
                                    </p>
                        </div>
                        
                        <div style="border: 1px dashed grey; margin: 5px; padding: 5px;">
                            <h2>Parsing options</h2>
                            <input type ="checkbox" id="preserveOrder" > Preserve Order<br>
                            <input type ="checkbox" id="parseCDATA" checked="true" > Parse CDATA as separate property<br>
                            <input type ="checkbox" id="alwaysCreateTextNode" > Always create a separate property for text value of a tag. <br>
                            <input type ="checkbox" id="trimValues" checked="true" > Trim<br>
                            <input type="checkbox" id="ignoreAttributes" checked="true"> Ignore attributes <br>
                            <input type="checkbox" id="attributesGroupName"> Group all the attributes  <br>
                            <input type ="checkbox" id="allowBooleanAttributes"> Allow Boolean Attributes <br>
                            <input type="checkbox" id="parseAttributeValue"> Parse attribute's value to float / integer / boolean.<br>
                            <input type="checkbox" id="parseNodeValue" checked="true"> Parse text-node's value to float / integer / boolean.<br>
                            <input type="checkbox" id="removeNSPrefix" checked="true"> Remove namespace string from tag and attribute names. <br>
                            <input type ="checkbox" id="leadingZeros" checked="true"> Parse Number with leading zeros<br>
                            <!-- <span class="clearfix">TagName to parse CDATA as separate property <input type="text" id="cdataTagName" style=" color: black; float:right;" ><br></span> -->
                            <div class="text-center" style="margin: 15px">
                                <button id="toJson" class="btn btn-primary" type="button">Parse to JSON >> </button>
                                <button id="toXml" class="btn btn-primary" type="button"> << Parse to XML</button>
                            </div>
                        </div>
                        <div style="border: 1px dashed grey; margin: 5px; padding: 5px;">
                            <h2>Validator options</h2>
                            <input type="checkbox" id="allowBooleanAttributes_v"> Allow Boolean Attributes<br>
                            <div class="text-center" style="margin: 15px">
                                <button id="validate" class="btn btn-primary" type="button">Validate XML >> </button>
                            </div>
                            
                        </div>
                        <div style="border: 1px dashed grey; margin: 5px; padding: 5px;">
                            <h2>Note!!</h2>
                            <p>We are not interested in your data. But we use Google analytics to improve the quality of our work and add new features.</p>
                            <p>You can use this application offline. Or stop google analytics using browser plugins. We're still happy to serve our services.</p>
                        </div>
                </div>
                <div class="col-md-4">
                        <span class="float-right" style="color: white"><span id="lengthoutput" style="margin:5px">0</span> bytes</span>
                    <textarea id="result" style="width: 100%; height: 100%" class="form-control" placeholder="Output"></textarea>
                </div>
            </div>
        </div>
        
    <script>
        let highlightedLine = null;
        let editor;

        function updateLength(){
            const xmlData = editor.getValue();
            $("#lengthxml")[0].innerText = xmlData.replace(/>\s*</g, "><").length;
        }

        function onChange(){
            highlightLine();
            updateLength();
        }
        function highlightLine(n) {
            if (n) {
                unhighlightLine();
                highlightedLine = editor.addLineClass(n - 1, 'background', 'alert-danger');
                editor.setCursor(n);
            }else{
                unhighlightLine()
            }
        }

        function unhighlightLine() {
            if (highlightedLine) {
                editor.removeLineClass(highlightedLine, 'background', 'alert-danger');
                highlightedLine = null;
            }
        }

        $( document ).ready(function() {
            //const parser = require("parser");
            editor = CodeMirror.fromTextArea(document.getElementById("txtXml"), {
                mode: "application/xml",
                styleActiveLine: true,
                lineNumbers: true,
                foldGutter: true,
                autofocus: true,
                gutters: ["CodeMirror-foldgutter"]
            });

            // when user types something, remove highlighting from "bad" line
            editor.on('change', () => onChange());
            editor.on('drop', () => onChange());
            
            /* $('#txtXml').on('input', function(){
                updateLength();
            }); */

            $('#toJson').on('click', function() {
                $('#result').val('');
                const parser = new fxp.XMLParser(buildParsingConfig());
                let result;
                try{
                    result = parser.parse(editor.getValue(),{
                        allowBooleanAttributes: $("#allowBooleanAttributes").prop("checked")
                    });
                    updateOutputLength(JSON.stringify(result));
                    $('#result').val(JSON.stringify(result,null,4));
                }catch(err){
                    $('#result').val(err);
                }
            });

            $('#toXml').on('click', function() {
                let input = $('#result').val().trim() ;
                if(input.length){
                    editor.setValue('');
                    const builder = new fxp.XMLBuilder(xmlBuilderOptions());
                    const result = builder.build(JSON.parse( $('#result').val() ));
                    editor.setValue('<?xml version="1.0"?>\n'+result);
                }else{
                    console.error("Empty input");
                }
            });

            $('#validate').on('click', function() {
                $('#result').val('');
                const parser = fxp.XMLValidator;
                const config = {
                    allowBooleanAttributes: $("#allowBooleanAttributes_v").prop("checked"),
                };
                const val = parser.validate(editor.getValue(), config);
                if(val === true){
                    $('#result').val("Valid XML");
                }else{
                    if (val.err.line) {
                        highlightLine(val.err.line);
                    }
                    $('#result').val(JSON.stringify(val,null,4));
                }
            });
            
            optionsLogic();
            $('#ignoreAttributes').on('change', function (){optionsLogic();});

            function buildParsingConfig(){
                const config = {
                    alwaysCreateTextNode: $("#alwaysCreateTextNode").prop("checked"),
                    attributeNamePrefix : "@_",
                    attributesGroupName: $("#attributesGroupName").prop("checked") ? "@" : false,
                    textNodeName : "#text",
                    ignoreAttributes : $("#ignoreAttributes").prop("checked"),
                    removeNSPrefix : $("#removeNSPrefix").prop("checked"),
                    parseNodeValue : $("#parseNodeValue").prop("checked"),
                    parseAttributeValue : $("#parseAttributeValue").prop("checked"),
                    allowBooleanAttributes: $("#allowBooleanAttributes").prop("checked"),
                    trimValues: $('#trimValues').prop("checked"), //Trim string values of tag and attributes
                    cdataTagName: $("#parseCDATA").prop("checked") ? "#cdata" : false,
                    preserveOrder: $("#preserveOrder").prop("checked"),
                    numberParseOptions:  {
                        hex: false,
                        leadingZeros: $("#leadingZeros").prop("checked")
                    }
                };

                return config;
            }

            function xmlBuilderOptions(){
                const defaultOptions = {
                    attributeNamePrefix : "@_",
                    attributesGroupName: $("#attributesGroupName").prop("checked") ? "@" : false,
                    textNodeName : "#text",
                    ignoreAttributes : $("#ignoreAttributes").prop("checked"),
                    cdataTagName: $("#parseCDATA").prop("checked") ? "#cdata" : false,
                    format: true,
                    indentBy: "  ",
                    suppressEmptyNode: false,
                    preserveOrder: $("#preserveOrder").prop("checked"),
                }

                return defaultOptions;
            }
            
            function optionsLogic(){
                const ignoreAttr = $('#ignoreAttributes').prop('checked');
                if(ignoreAttr){
                    $('#attributesGroupName').prop('checked', !ignoreAttr);
                    $('#parseAttributeValue').prop('checked', !ignoreAttr);
                    $('#allowBooleanAttributes').prop('checked', !ignoreAttr);
                }
                $('#attributesGroupName').attr('disabled', ignoreAttr);
                $('#parseAttributeValue').attr('disabled', ignoreAttr);
                $('#allowBooleanAttributes').attr('disabled', ignoreAttr);

                return;
            }

            

            function updateOutputLength(data){
                $("#lengthoutput")[0].innerText = data.length;
            }

            editor.setValue(`<?xml version="1.0"?>
<any_name>
    <person>
        <phone>+122233344550</phone>
        <name>Jack</name>
        <phone>+122233344551</phone>
        <age>33</age>
        <married firstTime="No">Yes</married>
        <birthday>Wed, 28 Mar 1979 12:13:14 +0300</birthday>
        <address>
            <city>New York</city>
            <street>Park Ave</street>
            <buildingNo>1</buildingNo>
            <flatNo>1</flatNo>
        </address>
        <address>
            <city>Boston</city>
            <street>Centre St</street>
            <buildingNo>33</buildingNo>
            <flatNo>24</flatNo>
        </address>
    </person>
    <person>
        <phone>+122233344553</phone>
        <name>Boris</name>
        <phone>+122233344554</phone>
        <age>34</age>
        <married firstTime="Yes">Yes</married>
        <birthday>Mon, 31 Aug 1970 02:03:04 +0300</birthday>
        <address>
            <city>Moscow</city>
            <street>Kahovka</street>
            <buildingNo>1</buildingNo>
            <flatNo>2</flatNo>
        </address>
        <address>
            <city>Tula</city>
            <street>Lenina</street>
            <buildingNo>3</buildingNo>
            <flatNo>78</flatNo>
        </address>
    </person>
</any_name>`);
            updateLength();
        });
    </script>
    <script async defer src="https://buttons.github.io/buttons.js"></script>
    
    </body>
</html>
